<?php

namespace Managers;

use \G4T\Util\ClassMetadata;
use \G4T\Util\ArrayUtil;

class News extends BaseManager implements CrudManager, MatchesManager
{
    const TABLE = '\Catalog\News';
    protected $__table = self::TABLE;
    protected $cacheNames = array('news_popular', 'news_recent');
    const TIME_IN_CACHE = 600;

    protected static $validSortColumns = array('id', 'date', 'img');

    protected static $validSortOrders = array('asc', 'desc');

    /**
     * $limit, $offset - используются в BaseManager'е.
     * Если они указаны, BaseManager::createQueryBuilder() автоматически их подставит в запрос.
     * Лучше без особой потребности не прописывать им значение вручную.
     */
//    protected $limit=4;
    protected $limit1 = 8;
    protected $limit2=5;
    protected $limit3=20;

    public function getList($column = 'id', $order = 'desc')
    {
        // Ну загружаем теги, для пагинации
        $qb = $this->createBaseQueryBuilder();
        $order = is_string($order) ? strtolower(trim($order)) : $order;

        $this->setOrder($qb, $column, $order);

        $res = $qb->getQuery()->getArrayResult();
        return $res;
    }

    protected function setOrder(\Doctrine\ORM\QueryBuilder $qb, $column, $order = 'asc')
    {
        $column = is_string($column) ? strtolower(trim($column)) : false;
        if (in_array($column, self::$validSortColumns)) {
            $order = is_string($order) ? strtolower(trim($order)) : 'asc';
            if (in_array($order, self::$validSortOrders)) {
                $qb->addOrderBy("n.{$column}", $order);
            } else {
                $qb->addOrderBy("n.{$column}");
            }
        }
    }

    public function createBaseQueryBuilder()
    {
        $qb = parent::createQueryBuilder()
            ->select('n, r, i')
            ->from($this->__table, 'n')
            ->join('n.rubric', 'r')
            ->join('n.issue', 'i')
            ->andWhere('n.isDel = 0')
            ->andWhere('r.isDel = 0');
        return $qb;
    }

    public function getListWithCommentsCount()
    {
        $news = $this->getList();
        $news = $this->addCommentsCount($news);
        return $news;
    }

    public function addCommentsCount($news)
    {
        $commentsManager = new Comments();
        $comments = $commentsManager->getCountByArticles($news);
        foreach ($news as &$article) {
            $article['comments_count'] = 0;
            foreach ($comments as $comment) {
                if ($comment[0]['news']['id'] == $article['id']) {
                    $article['comments_count'] = $comment['total'];
                }
            }
        }
        return $news;
    }

    public function getById($id)
    {
        $qb = $this->createQueryBuilder()
            ->andWhere('n.id = :id')->setParameter('id', $id);
        $res = $qb->getQuery()->getArrayResult();
        return count($res) ? $res[0] : false;
    }

    public function  getTopNews($top=1)
      {
          $qb = $this->createQueryBuilder()
              ->andWhere('n.top = :top')->setParameter('top', $top)->setMaxResults($this->limit1);
          $res = $qb->getQuery()->getArrayResult();
          return count($res) ? $res : false;
      }

    protected function createQueryBuilder()
    {
        $qb = parent::createQueryBuilder()
            ->select('n, r, t , i')
            ->from($this->__table, 'n')
            ->join('n.rubric', 'r')
            ->join('n.issue', 'i')
            ->leftJoin('n.tags', 't')
            ->andWhere('n.isDel = 0')
            ->andWhere('r.isDel = 0');
        return $qb;
    }

    public function getRub4News(){
        $qb = parent::createQueryBuilder()
        ->select('n, r')
        ->from($this->__table, 'n')
        ->join('n.rubric', 'r')
        ->andWhere('n.isDel = 0')
        ->andWhere('r.isDel = 0')
        ->groupBy('n.rubric')
        ->setMaxResults($this->limit3);
        $res = $qb->getQuery()->getArrayResult();
        $rubrics=array();
        $count=0;
        foreach ($res as $one)
        {

            $rubrics[$count]['id']=$one['rubric']['id'];
            $rubrics[$count]['name']=$one['rubric']['name'];
            $count++;
        }
        return $rubrics;
    }
public function  getComments($id){
     $qb = parent::createQueryBuilder()
      ->select('n.id, r')
      ->from($this->__table, 'n')
      ->join('n.rubric', 'r')
      ->andWhere('n.isDel = 0')
      ->andWhere('r.isDel = 0')
      ->groupBy('n.rubric')
      ->setMaxResults($this->limit3);
      $res = $qb->getQuery()->getArrayResult();
}
    /**
     * Создает новую запись.
     * @param array $values
     */
    public function create(array $values)
    {
        $entity = new \Catalog\News();
        $entity->setViews(0);
        $entity->setIsDel(false);
        $entity->setDate(new \DateTime());
        $entity->setPublishDate(new \DateTime());
        $this->setEntityValues($entity, $values);
        $this->_em->persist($entity);
        $this->flush();
        return $entity;
    }

    /**
     * Обновляет запись.
     * @param array $values
     */
    public function update(array $values)
    {
        $entity = $this->find($values['id']);
        $this->setEntityValues($entity, $values);
        $this->_em->persist($entity);
        $this->flush();
        return $entity;
    }

    public function setEntityValues(\Catalog\News $entity, array $values)
    {
        $entity->setContent($values['content']);
        $entity->setPublic($values['public']);
        $entity->setTitle($values['title']);
        $entity->setTop($values['top']);
        $rubricRef = $this->_em->getReference(Rubrics::TABLE, $values['rubric']);
        $entity->setRubric($rubricRef);
        if (!empty($values['img'])) {
            $img = $this->handleImage($values['img']);
            $entity->setImg($img);
        }
        $entity->setSource($values['source']);
        $entity->setAuthor($values['author']);
        $entity->setIntroduction($values['introduction']);
        $issueRef = $this->_em->getReference(Issue::TABLE, $values['issue']);
        $entity->setIssue($issueRef);
        $entity->setAllowComments($values['allowComments']);
        $this->handleTags($entity, $values['auto']);
    }

    private function handleImage($name)
    {
        $defaultDir = \Zend_Registry::get('config')->upload->dir;
        $uploadDir = dirname(APPLICATION_PATH) . DIRECTORY_SEPARATOR . $defaultDir;
        $uploadFile = $uploadDir . DIRECTORY_SEPARATOR . $name;
        $uploadFile = Utils::sanitizePath($uploadFile);
        $parameters = \Zend_Registry::get('config')->news->image;
        /* @var \Zend_Config $parameters */
        $saveDir = dirname(APPLICATION_PATH) . DIRECTORY_SEPARATOR . $parameters->get('dir');
        $saveDir = Utils::sanitizePath($saveDir);
        if (!is_writable($saveDir)) {
            throw new \Exception("$saveDir is not writable.");
        }
        $count = 0;
        do {
            $fileName = Utils::sanitizePath($saveDir . DIRECTORY_SEPARATOR . pathinfo($name, PATHINFO_FILENAME) .
                '_' . $count . '.' . pathinfo($name, PATHINFO_EXTENSION));
            $count++;
        } while (file_exists($fileName));

        rename($uploadFile, $fileName);

        $bigParameters = \Zend_Registry::get('config')->news->image->big;
        $bigImageCutter = new \Managers\Images\Cutter(new \Managers\Naming\Image(),
            $bigParameters->width, $bigParameters->height);
        $defaultName = $bigImageCutter->transform($fileName);

        $smallParameters = \Zend_Registry::get('config')->news->image->small;
        $smallImageCutter = new \Managers\Images\Cutter(new \Managers\Naming\SmallImage(),
            $smallParameters->width, $smallParameters->height);
        $smallImageCutter->transform($fileName);

        unlink($fileName);

        return Utils::getRelUrl($defaultName);
    }

    private function handleTags(\Catalog\News $entity, $tags)
    {
        $entityTags = $entity->getTags();
        $entityTags->clear();

        if (mb_strlen($tags) > 0) {
            $searcher = new \Managers\Searchers\StrictTags();
            $results = $searcher->addName($tags)->getResult();
            $result = $results[0];

            if (isset($result['words'])) {
                $decorator = new \Managers\Decorators\UnfoundWords();
                $tagsManager = new Tags();
                $newTags = $tagsManager->createByWords($decorator->decorate($result['words']));

                // добавляем новые теги
                foreach ($newTags as $tag) {
                    $entityTags->add($tag);
                }
            }

            // добавляем существующие теги
            if (isset($result['matches'])) {
                foreach ($result['matches'] as $match) {
                    $tagRef = $this->_em->getReference(Tags::TABLE, $match['id']);
                    if ($tagRef) {
                        $entityTags->add($tagRef);
                    }
                }
            }
        }
    }

    public function getPopular()
    {
        $cacheName = $this->cacheNames[0];
        $res = $this->_getCacheManager()->load($cacheName);
        if (!$res) {
            $qb = $this->createQueryBuilder()
                ->addOrderBy('n.views', 'DESC')
                ->setMaxResults($this->limit2);
            $res = $qb->getQuery()->getArrayResult();
            $this->_getCacheManager()->save($res, $cacheName, array(), self::TIME_IN_CACHE);
        }
        return $res;
    }
    public function getPopularNews()
       {//пробовал ту что выше не работает
           // исправил [b17].
               $res = $this->getPopular();
           return $res;
       }

    public function getRecent()
    {
        $cacheName = $this->cacheNames[1];
        $res = $this->_getCacheManager()->load($cacheName);
        if (!$res) {
            $qb = $this->createQueryBuilder()
                ->addOrderBy('n.id', 'DESC');
            $res = $qb->getQuery()->getArrayResult();
            $this->_getCacheManager()->save($res, $cacheName, array(), self::TIME_IN_CACHE);
        }
        return $res;
    }

    public function getByMatches(array $matches)
    {
        if (!count($matches)) {
            return $matches;
        }
        $matchesIds = Utils::rebuildArray($matches);
        $qb = $this->createBaseQueryBuilder();
        $qb->andWhere($qb->expr()->in('n.id', $matchesIds));
        $res = $qb->getQuery()->getArrayResult();
        $res = Utils::sphinxSort($res, $matches);
        return $res;
    }

    public function getByIdWithCommentsAndSimilar($id, $limit=5)
    {
        $article = $this->getById($id);
        if ($article) {
            $article = $this->addMark($article);
            $article = $this->addComments($article);
            $article = $this->addSimilar($article, $limit);
            $article = $this->addVotable($article);
        }
        return $article;
    }

    private function addComments($article)
    {
        $commentsManager = new Comments();
        $article['comments'] = $commentsManager->getTreeList($article['id']);
        return $article;
    }

    private function addMark($article)
    {
        $marksManager = new Marks();
        $article['mark'] = $marksManager->getNewsRating($article['id']);
        return $article;
    }

    public function addSimilar($article, $limit=5)
    {
        $tags = $article['tags'];
        if (!count($tags)) {
            $article['similar'] = array();
            return $article;
        }
        $tagsIds = Utils::rebuildArray($tags);
        $qb = $this->createQueryBuilder();
        $qb->select('count(t.id) as total, n.id')
            ->andWhere('n.id != :exc')->setParameter('exc', $article['id'])
            ->andWhere($qb->expr()->in('t.id', $tagsIds))
            ->addOrderBy('total', 'DESC')
            ->addGroupBy('n.id');
        $res = $qb->getQuery()->setMaxResults($limit)->getArrayResult();

        $this->resetLimit();
        $article['similar'] = count($res) ? $this->getByMatches($res) : array();

        return $article;
    }

    private function addVotable($article)
    {
        $marksManager = new Marks();
        $article['votable'] = $marksManager->canVote($article['id'], $_SERVER['REMOTE_ADDR']);
        return $article;
    }

    public function getCount($onlyPublic = false)
    {
        $limit = $this->limit;
        $offset = $this->offset;
        $this->resetLimit();

        $qb = $this->createBaseQueryBuilder()
            ->select('count(n.id) as total');
        if ($onlyPublic) {
            $qb->andWhere('n.public = 1');
        }
        $res = $qb->getQuery()->getArrayResult();

        $this->setLimit($limit);
        $this->setOffset($offset);

        return $res[0]['total'];
    }

    public function allowComments($newsId)
    {
        $newsBuilder = new \Managers\Builder\NewsBuilder();
        $article = $newsBuilder->setId($newsId)->getOne();
        return $article ? $article['allowComments'] : false;
    }

    /**
     * Инкремент просмотров новости
     * @param $news_id
     */
    public function incrementViews($news_id){
        $news = $this->find($news_id);
        if($news){
            $news->setViews(1+$news->getViews()*1);
//            $this->_em->persist();
            $this->flush($news);
        }
    }

    public function getMostCommentable($limit)
    {
        $commentsManager = new Comments();
        $news = $commentsManager->getMostCommentable($limit);
        $res = $this->getByMatches($news);
        $res = $this->addCommentsCount($res);
        return $res;
    }

}
